let pc = require("./cp");
let xlsx = require("node-xlsx");
let path = require("path");
let dayjs = require("dayjs");
let crypto = require("crypto");
let aiyc = require("../ai/red/yc");
let blueyc = require("../ai/blue/yc");
let ryc = aiyc(1);
let byc = blueyc(1);
//加载文件模块
let fs = require("fs");

//二分边界查找
function efFind(arr, target) {
  let left = 0;
  let right = arr.length;
  while (left < right) {
    let mid = left + Math.floor((right - left) / 2);
    let m = arr[mid];
    if (m == target) {
      return mid;
    } else if (m > target) {
      right = mid;
    } else if (m < target) {
      left = mid + 1;
    }
  }
  return left - 1;
}

function findBall(redQz, blueQz, rn = 6, bn = 1) {
  let redBall = []; //红球结果
  let blueBall = [];
  let rsumArr = [0]; //红球权重和数组
  let bsumArr = [0]; //篮球权重和数组

  // 计算红球权重和数组
  for (let i = 0; i < redQz.length; i++) {
    rsumArr[i + 1] = rsumArr[i] + redQz[i];
  }
  // 计算蓝球权重和数组
  for (let j = 0; j < blueQz.length; j++) {
    bsumArr[j + 1] = bsumArr[j] + blueQz[j];
  }
  // 选红球
  while (redBall.length < rn) {
    //随机数 1 ~ 权重和
    let rnum = Math.floor(Math.random() * rsumArr[rsumArr.length - 1]);
    let newBall = efFind(rsumArr, rnum) + 1;
    if (!redBall.includes(newBall)) {
      redBall.push(newBall);
    }
  }
  // 选篮球
  while (blueBall.length < bn) {
    //随机数 1 ~ 权重和
    let bnum = Math.floor(Math.random() * bsumArr[bsumArr.length - 1]);
    let newBall = efFind(bsumArr, bnum) + 1 + "";
    if (!blueBall.includes(newBall)) {
      blueBall.push(newBall);
    }
  }

  redBall.sort((a, b) => a - b);
  blueBall.sort((a, b) => a - b);
  return [...redBall, ...blueBall];
}

function yhfindBall(rq, bq, rn = 6, bn = 1) {
  let rball = [
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
    22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
  ];
  let bball = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];

  let rqh = [];

  let bqh = [];

  let r = []; //选中红球
  let b = []; //选中蓝球

  // 选红球
  while (r.length < rn) {
    //重新计算权重和
    rqh = [0];
    for (let i = 0; i < rq.length; i++) {
      rqh[i + 1] = rqh[i] + rq[i];
    }
    //随机数 [0 ~ 权重和)
    let rnum = Math.floor(Math.random() * rqh[rqh.length - 1]);
    let index = efFind(rqh, rnum);
    if (!r.includes(rball[index])) {
      r.push(rball[index]);
    }
    rq.splice(index, 1);
    rball.splice(index, 1);
  }
  // 选篮球
  while (b.length < bn) {
    bqh = [0];
    for (let i = 0; i < bq.length; i++) {
      bqh[i + 1] = bqh[i] + bq[i];
    }
    //随机数 1 ~ 权重和
    let bnum = Math.floor(Math.random() * bqh[bqh.length - 1]);
    let index = efFind(bqh, bnum);
    if (!b.includes(bball[index])) {
      b.push(bball[index] + "");
    }
    bq.splice(index, 1);
    bball.splice(index, 1);
  }

  r.sort((a, bb) => a - bb);
  b.sort((a, bb) => a - bb);
  return [...r, ...b];
}

async function start(n = 10) {
  let res = await pc();
  console.log("\x1B[34m%s\x1B[0m", "-------------爬虫结果-----------");
  console.log(res);
  console.log("\x1B[34m--------------------------------\x1B[0m");
  let arr = [];

  //-------第二代优化算法-----------
  let { red, oldRed } = res;
  let selectTimes = 1;
  while (arr.length < 6 && selectTimes < 100) {
    let a = findBall(res.wzjred, res.wzjblue);
    let qushi = false;
    for (let v = 0; v < red.length; v++) {
      let x = a[v] - red[v] >= 0; //新选择的值是上升还是下降
      let y = red[v] - oldRed[v] > 0; //之前中奖值是上升还是下降
      qushi = x == y;
      if (qushi) {
        //当  上升趋势相同时为不合格选号
        break;
      }
    }
    !qushi && arr.push(a);
    selectTimes++;
  }

  if (selectTimes >= 100 && arr.length == 0) {
    console.log(`\x1B[31m =======选号超过100次，未选到合适号码====  \x1B[0m`);
  } else {
    console.log("\x1B[32m =========选出优化后的合适号码======  \x1B[0m");
    exportExcel(arr, res.time, "--优化"); //导出优化
  }
  //-------第二代优化算法-----------

  //-------第二代算法-----------
  let warr = [];
  for (let i = 1; i <= n; i++) {
    warr.push(findBall(res.wzjred, res.wzjblue));
  }
  let cpwarr = JSON.parse(JSON.stringify(warr));
  //-------第四代算法-----------
  let pcball = excludeBall(warr, res); //排除法选好
  //-------第四代算法-----------

  warr.push(findBall(res.wzjred, res.wzjblue, 7, 2)); //复式选号
  warr.push([]);
  warr.push(...pcball);
  exportExcel(warr, res.time); //导出未优化号码
  //-------第二代算法-----------

  //-------第三代算法-----------
  let tarr = [];

  for (let i = 1; i <= n; i++) {
    let rqz = JSON.parse(JSON.stringify(res.wzjred));
    let bqz = JSON.parse(JSON.stringify(res.wzjblue));
    tarr.push(yhfindBall(rqz, bqz));
  }
  let rqz = JSON.parse(JSON.stringify(res.wzjred));
  let bqz = JSON.parse(JSON.stringify(res.wzjblue));
  tarr.push(yhfindBall(rqz, bqz, 7, 2)); //复式选号

  let pcball2 = excludeBall(cpwarr, res, tarr); //排除法选好
  tarr.push([]);
  tarr.push(...pcball2);
  exportExcel(tarr, res.time, "--第三代"); //导出第三代号码

  saveZj([...res.red, ...res.blue], res.time);
  //-------第三代算法-----------
}
start();

function exportExcel(data, time, optimize = "") {
  //定义列宽，使用默认列宽，可以忽略
  // let sheetOptions = { "!cols": [{ wch: 10 }, { wch: 50 }, { wch: 20 }] };
  //生成buffer
  let date = dayjs(new Date()).format("YYYY-MM-DD");
  let dir = path.join(__dirname, "res/" + date);
  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir);
  }
  data.unshift([
    "红球1",
    "红球2",
    "红球3",
    "红球4",
    "红球5",
    "红球6",
    "蓝球1",
    time - 0 + 1,
  ]);

  let buffer = xlsx.build([{ name: "结果", data: data }]);
  //导出
  let filename = "双球" + optimize + Math.random().toString(16).slice(2, 6);
  fs.writeFileSync(
    path.join(__dirname, `/res/${date}/${filename}.xlsx`),
    buffer,
    { flag: "w" }
  );
}

function saveZj(res, time) {
  res.unshift(time);
  let data = res;
  let filepath = path.join(__dirname, "/zj/中奖号码.xlsx");
  if (fs.existsSync(filepath)) {
    let history = xlsx.parse(filepath);
    //输出一下
    let arr = history[0].data;
    let newRes = arr[arr.length - 1];
    let oldTime = newRes[0];
    if (oldTime == time) return;
    arr.push(data);
    data = arr;
  } else {
    data.unshift([
      "时间",
      "红球1",
      "红球2",
      "红球3",
      "红球4",
      "红球5",
      "红球6",
      "蓝球1",
    ]);
  }

  let buffer = xlsx.build([{ name: "中奖结果", data: data }]);
  //导出
  fs.writeFileSync(filepath, buffer, { flag: "w" });
}

function excludeBall(xh, res, oth = []) {
  //let aibball = blueyc();
  let result = [];
  for (let i = 0; i < xh.length; i++) {
    let item = xh[i];
    let o = oth[i] ? oth[i] : [];
    let xzh = Array.from(
      new Set([...item.slice(0, 6), ...ryc, ...o.slice(0, 6)])
    );
    let bxzh = Array.from(
      new Set([...item.slice(6, 7), ...byc, ...o.slice(6, 7)])
    );
    let rqz = JSON.parse(JSON.stringify(res.wzjred));
    let bqz = JSON.parse(JSON.stringify(res.wzjblue));
    let rball = Array.from({ length: 33 }, (_, i) => i + 1);
    let bball = Array.from({ length: 16 }, (_, i) => i + 1);
    for (let idx of xzh) {
      rqz[idx - 1] = 0;
      rball[idx - 1] = 0;
    }
    for (let idx of bxzh) {
      bqz[idx - 1] = 0;
      bball[idx - 1] = 0;
    }
    rqz = JSON.parse(JSON.stringify(rqz.filter((item) => item > 0)));
    rball = JSON.parse(JSON.stringify(rball.filter((item) => item > 0)));
    bqz = JSON.parse(JSON.stringify(bqz.filter((item) => item > 0)));
    bball = JSON.parse(JSON.stringify(bball.filter((item) => item > 0)));
    result.push(excludeFind(rball, bball, rqz, bqz));
  }

  return result;
  //exportExcel(result, res.time, "--第四代"); //导出第三代号码
}

function excludeFind(rxh, bxh, rqz, bqz, rn = 6, bn = 1) {
  let r = []; //选中红球
  let b = []; //选中蓝球
  while (r.length < rn) {
    let rsum = [0];
    for (let i = 0; i < rqz.length; i++) {
      rsum[i + 1] = rqz[i] + rsum[i];
    }
    //随机数 [0 ~ 权重和)
    let rnum = Math.round(Math.random() * rsum[rsum.length - 1]);
    let index = efFind(rsum, rnum);
    if (!r.includes(rxh[index])) {
      r.push(rxh[index]);
    }
    rqz.splice(index, 1);
    rxh.splice(index, 1);
  }
  // 选篮球
  while (b.length < bn) {
    let bsum = [0];
    for (let i = 0; i < bqz.length; i++) {
      bsum[i + 1] = bsum[i] + bqz[i];
    }
    //随机数 1 ~ 权重和
    let bnum = Math.round(Math.random() * bsum[bsum.length - 1]);
    let index = efFind(bsum, bnum);
    if (!b.includes(bxh[index])) {
      b.push(bxh[index] + "");
    }
    bxh.splice(index, 1);
    bqz.splice(index, 1);
  }
  r.sort((a, bb) => a - bb);
  b.sort((a, bb) => a - bb);
  return [...r, ...b];
}
